using System;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace Pegasus.Windows.Forms.Explorer
{
	/// <summary>
	/// Represents a node in the explorer view control.
	/// </summary>
	public class ExplorerNode
	{
		// Local Instance Values
		private ExplorerView m_explorerView = null;
		private ExplorerNodeCollection m_childNodes = new ExplorerNodeCollection();
		private ExplorerNode m_parent = null;
		private string m_path = "\\";

		private string m_text = string.Empty;
		private string m_key = null;
		private object m_tag = null;
		private bool m_loadChildrenOnDemand = false;
		private bool m_childrenLoaded = false;
		private bool m_showInTree = true;
		private int m_imageIndex = -1;

		/// <summary>
		/// Initializes a new instance of the <see cref="ExplorerNode"/> class.
		/// </summary>
		public ExplorerNode()
		{
			m_key = GetHashCode().ToString();

			// Bind to the child node events
			m_childNodes.OnNodeAdded += new EventHandler<ExplorerEventArgs>( ChildNodes_OnNodeAdded );
			m_childNodes.OnNodeRemoved += new EventHandler<ExplorerEventArgs>( ChildNodes_OnNodeRemoved );
			m_childNodes.OnCollectionClearing += new EventHandler<EventArgs>( ChildNodes_OnCollectionClearing );
			m_childNodes.OnCollectionCleared += new EventHandler<EventArgs>( ChildNodes_OnCollectionCleared );
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="ExplorerNode"/> class.
		/// </summary>
		/// <param name="text">The text.</param>
		public ExplorerNode( string text )
			: this()
		{
			Text = text;
			BuildPath();
		}

		/// <summary>
		/// Gets or sets the text.
		/// </summary>
		/// <value>The text.</value>
		public string Text
		{
			get
			{
				return m_text;
			}

			set
			{
				m_text = value;
				BuildPath();
			}
		}

		/// <summary>
		/// Gets or sets the index of the image.
		/// </summary>
		/// <value>The index of the image.</value>
		public int ImageIndex
		{
			get
			{
				return m_imageIndex;
			}

			set
			{
				m_imageIndex = value;
			}
		}

		/// <summary>
		/// Gets the parent.
		/// </summary>
		/// <value>The parent.</value>
		public ExplorerNode Parent
		{
			get
			{
				return m_parent;
			}
		}

		/// <summary>
		/// Gets the path.
		/// </summary>
		/// <value>The path.</value>
		public string Path
		{
			get
			{
				return m_path;
			}
		}

		/// <summary>
		/// Gets or sets a value indicating whether the node should be shown in tree.
		/// </summary>
		/// <value><c>true</c> then show node in tree; otherwise, <c>false</c>.</value>
		public bool ShowInTree
		{
			get
			{
				return m_showInTree;
			}
		
			set
			{
				m_showInTree = value;
			}
		}

		/// <summary>
		/// Gets the child nodes.
		/// </summary>
		/// <value>The nodes.</value>
		public ExplorerNodeCollection Nodes
		{
			get
			{
				return m_childNodes;
			}
		}

		/// <summary>
		/// Gets or sets the key for this node.
		/// </summary>
		/// <value>The key.</value>
		public string Key
		{
			get
			{
				return m_key;
			}

			set
			{
				m_key = value;
			}
		}

		/// <summary>
		/// Gets or sets the applicaiton tag object.
		/// </summary>
		/// <value>The tag.</value>
		public object Tag
		{
			get
			{
				return m_tag;
			}

			set
			{
				m_tag = value;
			}
		}

		/// <summary>
		/// Gets or sets a value indicating whether to load children on demand.
		/// </summary>
		/// <value>
		/// 	<c>true</c> if load children on demand; otherwise, <c>false</c>.
		/// </value>
		public bool LoadChildrenOnDemand
		{
			get
			{
				return m_loadChildrenOnDemand;
			}

			set
			{
				m_loadChildrenOnDemand = value;
			}
		}

		/// <summary>
		/// Gets or sets a value indicating whether [children loadded].
		/// </summary>
		/// <value><c>true</c> if [children loadded]; otherwise, <c>false</c>.</value>
		public bool ChildrenLoadded
		{
			get
			{
				return m_childrenLoaded;
			}

			set
			{
				m_childrenLoaded = value;
			}
		}

		/// <summary>
		/// Gets or sets the explorer view that this node belongs to.
		/// </summary>
		/// <value>The explorer view.</value>
		internal ExplorerView ExplorerView
		{
			get
			{
				return m_explorerView;
			}

			set
			{
				m_explorerView = value;
				foreach( ExplorerNode node in m_childNodes )
				{
					node.ExplorerView = m_explorerView;
				}
			}
		}

		/// <summary>
		/// Refreshes this instance.
		/// </summary>
		public virtual void RefreshNode()
		{
			m_childNodes.Clear();
			LoadChildNodes();

			OnRefresh();
		}

		/// <summary>
		/// Loads the children items.
		/// </summary>
		public virtual void LoadChildNodes()
		{
			OnLoadChildren();
			m_childrenLoaded = true;
		}

		/// <summary>
		/// Sets the parent data.
		/// </summary>
		/// <param name="parent">The parent.</param>
		internal void SetParent( ExplorerNode parent )
		{
			m_parent = parent;
			if( parent != null )
			{
				ExplorerView = parent.ExplorerView;
			}
			else
			{
				ExplorerView = null;
			}

			BuildPath();
		}

		/// <summary>
		/// Handles the OnNodeAdded event of the ChildNodes control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="args">The <see cref="Pegasus.Windows.Forms.Explorer.ExplorerEventArgs"/> instance containing the event data.</param>
		private void ChildNodes_OnNodeAdded( object sender, ExplorerEventArgs args )
		{
			args.Node.SetParent( this );
			m_explorerView.AddNode( args.Node );
		}

		/// <summary>
		/// Handles the OnNodeRemoved event of the ChildNodes control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="args">The <see cref="Pegasus.Windows.Forms.Explorer.ExplorerEventArgs"/> instance containing the event data.</param>
		private void ChildNodes_OnNodeRemoved( object sender, ExplorerEventArgs args )
		{
			args.Node.SetParent( null );
			m_explorerView.RemoveNode( args.Node );
		}

		/// <summary>
		/// Handles the OnCollectionClearing event of the ChildNodes control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="args">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		private void ChildNodes_OnCollectionClearing( object sender, EventArgs args )
		{
			// Clear all the child nodes parent data.
			foreach( ExplorerNode node in m_childNodes )
			{
				node.SetParent( null );
			}
		}

		/// <summary>
		/// Handles the OnCollectionCleared event of the ChildNodes control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="args">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		private void ChildNodes_OnCollectionCleared( object sender, EventArgs args )
		{
			m_explorerView.RemoveNodeChildren( this );
		}

		/// <summary>
		/// Builds the path.
		/// </summary>
		private void BuildPath()
		{
			StringBuilder newPath = new StringBuilder();
			newPath.Append( "\\" );
			newPath.Append( m_text );

			ExplorerNode parent = m_parent;
			while( parent != null )
			{
				newPath.Insert( 0, parent.Text );
				newPath.Insert( 0, "\\" );

				parent = parent.Parent;
			}

			m_path = newPath.ToString();
		}

		/// <summary>
		/// Called when the node is asked to refresh.
		/// </summary>
		protected virtual void OnRefresh()
		{
			if( Refresh != null )
			{
				Refresh( this, new ExplorerEventArgs( this ) );
			}
		}

		/// <summary>
		/// Fired when the node needs to have it's children loaded.
		/// </summary>
		public event EventHandler<ExplorerEventArgs> Refresh;


		/// <summary>
		/// Called when the children of this node need to be loaded.
		/// </summary>
		protected virtual void OnLoadChildren()
		{
			if( LoadChildren != null )
			{
				LoadChildren( this, new ExplorerEventArgs( this ) );
			}
		}

		/// <summary>
		/// Fired when the node needs to have it's children loaded.
		/// </summary>
		public event EventHandler<ExplorerEventArgs> LoadChildren;
	}
}
